#include "base/blocking_queue.h"

#include <string>
#include <iostream>
#include <thread>
#include <vector>
#include <chrono>

void get_value(BlockingQueue<std::string>& que, int count) {
    puts("wait...");
    for (int i = 0; i < count; i++) {
        que.wait_and_pop();
    }
}

void add_value(BlockingQueue<std::string>& que, int count) {
    for (int i = 0; i < count; i++) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        que.push(std::to_string(i));
    }
}


int main() {
    BlockingQueue<std::string> que;
    // 单线程测试
    for (int i = 0; i < 100000; i++) {
        que.push(std::to_string(i));
    }
    std::cout << que.size() << std::endl;   // 100000
    std::cout << que.empty() << std::endl;  // 0
    std::cout << que.front() << std::endl;  // 0
    std::cout << que.back() << std::endl;   // 99999
    
    for (int i = 0; i < 100000; i++) {
        auto p = que.wait_and_pop();
        //std::cout << *p << std::endl;
    }

    auto p = que.try_pop();
    if (p == nullptr) {
        std::cout << "que is empty" << std::endl;
    }

    // 测试多线程 push
    std::vector<std::thread> threads;
    for (int i = 0; i < 4; i++) {
        threads.emplace_back([&que]{
            for (int j = 0; j < 1000000; j++) {
                que.push(std::to_string(j));
            }
        });
    }
    for (auto& t : threads) t.join();
    std::cout << que.size() << std::endl;   // 4000000
    que.clear();


    que = BlockingQueue<std::string>(3);

    std::thread t1(get_value, std::ref(que), 10);
    std::thread t2(add_value, std::ref(que), 5);
    std::thread t3(add_value, std::ref(que), 5);
    t1.join();
    t2.join();
    t3.join();
    std::cout << que.size() << std::endl;   // 0


    std::thread t4([&que]{
        for (int i = 0; i < 4; i++) {
            que.push(std::to_string(i));
        }
    });

    std::thread t5([&que]{
        std::this_thread::sleep_for(std::chrono::seconds(1));
        std::cout << *que.wait_and_pop() << std::endl;  // 0
    });

    t4.join();
    t5.join();
    
    return 0;
}